"""
The is doc
"""

import logging
from datetime import timedelta

from django.contrib.auth import (
    get_user_model,
    authenticate,
    login,
    logout,
)

from django.core.cache import cache
from django.conf import settings
from django.views import View
from django.http import HttpRequest
from django.db import transaction
from django.utils.decorators import method_decorator
from django.utils import timezone
from django.contrib.auth.base_user import AbstractBaseUser

from rest_framework.parsers import JSONParser

from app_common import (
    app_try,
    app_page,
    app_except,
    app_str_check,
    app_sms,
    json_response_utf8_ok,
)

from . import models, ser, wx_api, wx_pay, access_auth

logger = logging.getLogger("log")


# Create your views here.


# admin api
@method_decorator([app_try], name="dispatch")
@method_decorator(access_auth.owner_access, name="delete")
@method_decorator(access_auth.owner_access, name="get")
class AdminLoginView(View):
    """管理员登录"""

    def get(self, request, *args, **kwargs):
        """查询当前管理员"""
        user: AbstractBaseUser = request.user
        u_s = ser.AppAdminSer(user)
        return json_response_utf8_ok({"data": u_s.data})

    def post(self, request, *args, **kwargs):
        # if debug create default user admin:admin
        _model = get_user_model()
        _admin = _model.objects.filter(username="admin").first()
        if not _admin:
            _model.objects.create_superuser(
                email="myemail@test.com",
                username="admin",
                password="c0fe91d7d275420d93bffda45990dfdb",
                user_type=models.WxUser.UserType.OWNER.value,
            )

        body: dict = JSONParser().parse(request)

        username = body["username"]
        password = body["password"]
        user = authenticate(request, username=username, password=password)
        if user is not None:
            login(request, user)
        else:
            if request.user.is_authenticated:
                logout(request)
            raise app_except.AdminLoginFail

        u_s = ser.AppAdminSer(user)
        return json_response_utf8_ok({"data": u_s.data})

    def delete(self, request, *args, **kwargs):
        user: AbstractBaseUser = request.user
        if not user:
            raise app_except.NoAccess
        logout(request)
        return json_response_utf8_ok({"info": f"{user.get_username()} logout"})


@method_decorator(access_auth.owner_access, name="dispatch")
class AdminWxUserView(View):
    """管理员管理 wx 用户接口"""

    def get(self, request, *args, **kwargs):
        """doc"""
        query_user_type = request.GET.get("query_user_type", None)
        if query_user_type:
            return json_response_utf8_ok({"data": models.WxUser.UserType.values})

        objs = models.WxUser.objects.filter(deleted=False)

        # 根据电话号查询用户
        telephone = request.GET.get("telephone", None)
        if telephone:
            objs = objs.filter(telephone__contains=telephone)

        nick_name = request.GET.get("nick_name", None)
        if nick_name:
            objs = objs.filter(nick_name=nick_name)

        _objs, num_pages = app_page.page(request, objs)
        m_s = ser.WxUserSer(_objs, many=True)
        return json_response_utf8_ok({"data": m_s.data, "num_pages": num_pages})

    @transaction.atomic
    def post(self, request, *args, **kwargs):
        """创建 不需要微信登录的用户， 只用于店长帮助记录用户消费"""
        body: dict = JSONParser().parse(request)
        now = timezone.now()
        bulk_user = []
        for info in body["list"]:
            nick_name = info["nick_name"]
            telephone = info["telephone"]
            if len(telephone) != 11:
                raise app_except.ValueErr(msg="电话号码必须为11位")
            user_type = models.WxUser.UserType.CUSTOM.value
            bulk_user.append(
                models.WxUser(
                    username=nick_name,
                    nick_name=nick_name,
                    telephone=telephone,
                    user_type=user_type,
                    created_at=now,
                )
            )
        models.WxUser.objects.bulk_create(bulk_user)

        objs = models.WxUser.objects.filter(deleted=False).filter(created_at=now)
        _objs, num_pages = app_page.page(request, objs)
        m_s = ser.WxUserSer(_objs, many=True)
        return json_response_utf8_ok({"data": m_s.data, "num_pages": num_pages})

    @transaction.atomic
    def put(self, request, *args, **kwargs):
        """doc"""
        body: dict = JSONParser().parse(request)
        uuids = []

        readonly_attrs = {
            _key: True for _key in ["openid", "remain_money", "total_recharge"]
        }

        for user_info in body["list"]:
            user_info = dict(user_info)
            _uuid = user_info.pop("uuid")
            uuids.append(_uuid)
            for key in user_info:
                if key in readonly_attrs:
                    raise app_except.ValueErr(msg=f"不可更新属性: {readonly_attrs}")

            obj = (
                models.WxUser.objects.filter(deleted=False)
                .filter(uuid=_uuid)
                .select_for_update()
                .first()
            )
            if not obj:
                raise app_except.ObjNotExist(msg=f"用户不存在: {_uuid}")

            obj_s = ser.WxUserSer(obj, data=user_info, partial=True)
            obj_s.is_valid(raise_exception=True)
            obj_s.save()

        objs = models.WxUser.objects.filter(deleted=False).filter(uuid__in=uuids)
        _objs, num_pages = app_page.page(request, objs)
        m_s = ser.WxUserSer(_objs, many=True)
        return json_response_utf8_ok({"data": m_s.data, "num_pages": num_pages})

    @transaction.atomic
    def delete(self, request, *args, **kwargs):
        return json_response_utf8_ok({"data": "undo"})


@method_decorator(access_auth.owner_access, name="dispatch")
class RechargePromotionView(View):
    """管理员管理 wx 用户接口"""

    def get(self, request, *args, **kwargs):
        """doc"""
        objs = models.RechargePromotion.objects.filter(deleted=False)
        _objs, num_pages = app_page.page(request, objs)
        m_s = ser.RechargePromotionSer(_objs, many=True)
        return json_response_utf8_ok({"data": m_s.data, "num_pages": num_pages})

    @transaction.atomic
    def post(self, request, *args, **kwargs):
        """doc"""
        wxuser: models.WxUser = request.user
        body: dict = JSONParser().parse(request)
        now = timezone.now()
        _bulk_create = []

        for _info in body["list"]:
            _info = dict(_info)
            _info["created_at"] = now
            _info["user_uuid"] = wxuser.uuid

            _bulk_create.append(models.RechargePromotion(**_info))

        # this objs return by bulk_create does not have uuid ... fields which created auto
        incomplete_objs = models.RechargePromotion.objects.bulk_create(_bulk_create)

        objs = models.RechargePromotion.objects.filter(deleted=False).filter(
            created_at=now
        )
        _objs, num_pages = app_page.page(request, objs)
        m_s = ser.RechargePromotionSer(_objs, many=True)
        return json_response_utf8_ok({"data": m_s.data, "num_pages": num_pages})

    @transaction.atomic
    def put(self, request, *args, **kwargs):
        """doc"""
        body: dict = JSONParser().parse(request)
        uuids = []

        for _info in body["list"]:
            _info = dict(_info)
            _uuid = _info.pop("uuid")
            uuids.append(_uuid)

            obj = (
                models.RechargePromotion.objects.filter(deleted=False)
                .filter(uuid=_uuid)
                .select_for_update()
                .first()
            )
            if not obj:
                raise app_except.ObjNotExist(msg=f"Promotion 不存在: {_uuid}")

            obj_s = ser.RechargePromotionSer(obj, data=_info, partial=True)
            obj_s.is_valid(raise_exception=True)
            obj_s.save()

        objs = models.RechargePromotion.objects.filter(deleted=False).filter(
            uuid__in=uuids
        )
        _objs, num_pages = app_page.page(request, objs)
        m_s = ser.RechargePromotionSer(_objs, many=True)
        return json_response_utf8_ok({"data": m_s.data, "num_pages": num_pages})

    @transaction.atomic
    def delete(self, request, *args, **kwargs):
        body: dict = JSONParser().parse(request)
        uuids = body["list"]
        n = (
            models.RechargePromotion.objects.filter(deleted=False)
            .filter(uuid__in=uuids)
            .update(deleted=True)
        )
        if 0 == n:
            raise app_except.ObjNotExist(msg=f"{uuids}")
        return json_response_utf8_ok({"data": n})


@method_decorator(access_auth.owner_access, name="dispatch")
class OwnerStoreGoodView(View):
    """管理员管理 wx 用户接口"""

    def get(self, request, *args, **kwargs):
        """doc"""
        objs = models.StoreGood.objects.filter(deleted=False)
        _objs, num_pages = app_page.page(request, objs)
        m_s = ser.OwnerStoreGoodSer(_objs, many=True)
        return json_response_utf8_ok({"data": m_s.data, "num_pages": num_pages})

    @transaction.atomic
    def post(self, request, *args, **kwargs):
        """doc"""
        wxuser: models.WxUser = request.user
        body: dict = JSONParser().parse(request)
        now = timezone.now()
        _bulk_create = []

        for _info in body["list"]:
            _info = dict(_info)
            _info["created_at"] = now
            _info["owner_uuid"] = wxuser.uuid

            # check attrs is exists
            _ = _info["type_uuid"]
            _ = _info["name"]
            _ = _info["display_url"]
            _ = _info["purchase_price"]
            _ = _info["price"]

            _bulk_create.append(models.StoreGood(**_info))

        # this objs return by bulk_create does not have uuid ... fields which created auto
        incomplete_objs = models.StoreGood.objects.bulk_create(_bulk_create)

        objs = models.StoreGood.objects.filter(deleted=False).filter(created_at=now)
        _objs, num_pages = app_page.page(request, objs)
        m_s = ser.OwnerStoreGoodSer(_objs, many=True)
        return json_response_utf8_ok({"data": m_s.data, "num_pages": num_pages})

    @transaction.atomic
    def put(self, request, *args, **kwargs):
        """doc"""
        body: dict = JSONParser().parse(request)
        uuids = []

        for _info in body["list"]:
            _info = dict(_info)
            _uuid = _info.pop("uuid")
            uuids.append(_uuid)

            obj = (
                models.StoreGood.objects.filter(deleted=False)
                .filter(uuid=_uuid)
                .select_for_update()
                .first()
            )
            if not obj:
                raise app_except.ObjNotExist(msg=f"商品不存在: {_uuid}")

            obj_s = ser.OwnerStoreGoodSer(obj, data=_info, partial=True)
            obj_s.is_valid(raise_exception=True)
            obj_s.save()

        objs = models.StoreGood.objects.filter(deleted=False).filter(uuid__in=uuids)
        _objs, num_pages = app_page.page(request, objs)
        m_s = ser.OwnerStoreGoodSer(_objs, many=True)
        return json_response_utf8_ok({"data": m_s.data, "num_pages": num_pages})

    @transaction.atomic
    def delete(self, request, *args, **kwargs):
        body: dict = JSONParser().parse(request)
        uuids = body["list"]
        n = (
            models.StoreGood.objects.filter(deleted=False)
            .filter(uuid__in=uuids)
            .update(deleted=True, del_race=timezone.now())
        )
        if 0 == n:
            raise app_except.ObjNotExist(msg=f"{uuids}")

        # 级联删除购物车中的该商品
        _del_date = timezone.now()
        del_good_car_count = (
            models.StoreGoodCarContent.objects.filter(deleted=False)
            .filter(good_uuid__in=uuids)
            .select_for_update()
            .update(deleted=True, del_race=_del_date)
        )
        # 日志打印被级联删除的购物车商品
        logger.error(f"del_good_car {del_good_car_count}, del at{_del_date}")
        return json_response_utf8_ok({"data": n})


@method_decorator(access_auth.owner_access, name="dispatch")
class UserRechargeView(View):
    """管理员管理 wx 用户接口"""

    def get(self, request, *args, **kwargs):
        """默认查询 31 天内的充值账单"""
        days = int(request.GET.get("days", 31))
        start_at = timezone.now() - timedelta(days=days)
        objs = (
            models.WxUserRemainMoneyRecord.objects.filter(deleted=False)
            .filter(created_at__gt=start_at)
            .exclude(actual_payment=0)
        )
        _objs, num_pages = app_page.page(request, objs)
        m_s = ser.WxUserRechargeRecordSer(_objs, many=True)
        return json_response_utf8_ok({"data": m_s.data, "num_pages": num_pages})

    @transaction.atomic
    def post(self, request, *args, **kwargs):
        """为用户充值"""
        now = timezone.now()

        body: dict = JSONParser().parse(request)
        _list = body.pop("list")

        for info in _list:
            user_uuid = info["user_uuid"]
            promotion_uuid = info["promotion_uuid"]

            _user = (
                models.WxUser.objects.filter(deleted=False)
                .filter(uuid=user_uuid)
                .select_for_update()
                .first()
            )
            if not _user:
                raise app_except.ObjNotExist(msg=f"用户不存在: {user_uuid}")

            _promotion = (
                models.RechargePromotion.objects.filter(deleted=False)
                .filter(uuid=promotion_uuid)
                .select_for_update()
                .first()
            )
            if not _promotion:
                raise app_except.ObjNotExist(msg=f"充值活动不存在: {promotion_uuid}")
            total_recharge = _promotion.actual_payment + _promotion.score

            _user.remain_money += total_recharge
            _user.save()

            # 发送余额变更短信
            app_sms.send_sms_remain_money_change(
                receiver=_user.telephone,
                change_type=app_sms.SMS_TYPE.RECHARGE.value,
                change_money=total_recharge,
                remain_money=_user.remain_money,
            )

            models.WxUserRemainMoneyRecord(
                created_at=now,
                user_uuid=user_uuid,
                remain_money=_user.remain_money,
                actual_payment=_promotion.actual_payment,
                score=_promotion.score,
                recharge_type=models.WxUserRemainMoneyRecord.RechargeType.OFF_LINE.value,
            ).save()

        objs = models.WxUserRemainMoneyRecord.objects.filter(deleted=False).filter(
            created_at=now
        )
        _objs, num_pages = app_page.page(request, objs)
        m_s = ser.WxUserRechargeRecordSer(_objs, many=True)
        return json_response_utf8_ok({"data": m_s.data, "num_pages": num_pages})
